using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Collections.Specialized;
using System.Linq;
using System.Xml.Serialization;

namespace Se.Framework.Common.Config.Urls
{
    [Serializable]
    public class ServiceUrlBuilder
    {
        public const string QueryStringInitialChar = "?";

        private const string UrlPathSplitter = "/";

        private const string UrlQueryStringSplitter = "&";

        private string baseUrl;

        public ServiceUrlBuilder()
        {
            Sections = new Collection<UrlSection>();
        }

        [XmlAttribute]
        public string Name { get; set; }

        [XmlAttribute]
        public string BaseUrl
        {
            get
            {
                return this.baseUrl;
            }
            set
            {
                this.baseUrl = value.TrimEnd("/".ToCharArray());
            }
        }

        [XmlArray]
        public Collection<UrlSection> Sections { get; set; }

        public string GetDynamycUrl(NameValueCollection values = null)
        {
            return DoValuesChange(values, true);
        }
  
        public override string ToString()
        {
            return string.Format("{0}: {1}", Name, DoValuesChange(null, false));
        }

        private string DoValuesChange(NameValueCollection values, bool throwOnError)
        {
            values = values ?? new NameValueCollection();

            List<UrlSection> sectionsCopy = new List<UrlSection>();
            string value;
            foreach (var item in Sections)
            {
                var newItem = item.Clone();
                value = values[item.Key];
                if (value != null)
                {
                    newItem.Value = value;
                }
                else if (newItem.Required && throwOnError)
                {
                    throw new InvalidOperationException(string.Format("The Parameter {0} is required on this URL", newItem.Key));
                }
                sectionsCopy.Add(newItem);
            }

            return GenerateUrl(sectionsCopy.OfType<UrlPathPart>().OrderBy(p => p.Order), sectionsCopy.OfType<UrlQueryStringPart>().OrderBy(p => p.Order));
        }

        private string GenerateUrl(IEnumerable<UrlSection> staticParameters, IEnumerable<UrlSection> dynamicParams)
        {
            var urlParams = string.Join(UrlPathSplitter, staticParameters);

            var queryString = string.Join(UrlQueryStringSplitter, dynamicParams);

            string result = string.Concat(BaseUrl, UrlPathSplitter, urlParams, QueryStringInitialChar, queryString)
                        .Replace(UrlPathSplitter + QueryStringInitialChar, QueryStringInitialChar);

            return result;
        }
    }
}